import {
  defineComponent,
  ref,
  computed,
  watch,
  onMounted,
  onUnmounted,
  getCurrentInstance,
  withDirectives,
  resolveDirective,
  h,
} from 'vue'
import { ClickOutside } from 'amtf/directives'
import VeCheckbox from 'amtf/components/checkbox'
import VeRadio from 'amtf/components/radio'
import { props, EMIT_EVENTS } from './props+'

import {
  getValByUnit,
  拼组件名,
  拼样式名,
  isFunction,
  isBoolean,
  getRandomId,
} from 'amtf/utils'
const 主名 = 'dropdown'
const 组件名 = 拼组件名(主名)
function _拼样式名(params) {
  return 拼样式名(主名, params)
}
import {
  getViewportOffset,
  getViewportOffsetWithinContainer,
} from 'amtf/utils'

export default defineComponent({
  name: 组件名,
  directives: { 'click-outside': ClickOutside },
  components: { VeCheckbox, VeRadio },
  props,
  setup(props, { emit, slots, expose }) {
    const vm = getCurrentInstance()
    const clickOutsideDirective = resolveDirective('click-outside')
    // console.log(`vm 👉`, vm)

    const internalVisible = ref(false)
    const internalOptions = ref([])
    const inputValue = ref('')
    const isDropdownShowTriggerClicked = ref(false)
    const rootId = ref('')
    const dropdownItemsPanelId = ref('')
    const popperAppendToEl = ref(null)
    const appendToElTagName = ref(null)

    const isDropdownVisible = computed(() =>
      props.isControlled ? props.visible : internalVisible.value
    )

    const getMaxWidth = computed(() => {
      let result = Infinity
      const maxWidth = props.maxWidth
      const width = props.width
      if (maxWidth && maxWidth > 0 && maxWidth > width) {
        result = maxWidth
      }
      return result
    })

    const selectedLabels = computed(() =>
      internalOptions.value
        .filter((x) => x.selected)
        .map((x) => (x.selected ? x.label : null))
    )

    const operationFilterClass = computed(() => ({
      [_拼样式名('filter-disable')]: selectedLabels.value.length === 0,
    }))

    const dropdownItemsClass = computed(() => ({
      [_拼样式名('dd')]: true,
      [_拼样式名('dd-show')]: isDropdownVisible.value,
    }))

    watch(
      () => props.modelValue,
      () => {
        init()
      }
    )

    watch(
      () => props.visible,
      (visible) => {
        setTimeout(() => {
          if (props.isControlled) {
            if (visible) {
              showDropDown()
            } else {
              hideDropDown()
            }
          }
        })
      },
      { immediate: true }
    )

    const init = () => {
      // console.log(`init props.modelValue 👉`, props.modelValue)
      internalOptions.value = [...props.modelValue]
      if (props.isInput) {
        setInputValue()
      }
    }
    init()

    const confirm = () => {
      // 使用户传入的v-model生效
      emit('input', internalOptions.value)
      // console.log(`触发事件 ing👇`)
      // console.log(`internalOptions.value 👉`, internalOptions.value)
      emit(EMIT_EVENTS.FILTER_CONFIRM, internalOptions.value)
      hideDropDown()
    }

    const reset = () => {
      if (internalOptions.value.some((x) => x.selected)) {
        internalOptions.value.forEach((x) => {
          if (x.selected) {
            x.selected = false
          }
          return x
        })
        // 使用户传入的v-model生效
        emit('input', internalOptions.value)
        // console.log(`触发事件 ing👇`)
        emit(EMIT_EVENTS.FILTER_RESET, internalOptions.value)
      }
      hideDropDown()
    }

    const showDropDown = () => {
      // console.log(`showDropDown ing👇`)
      const nextVisible = true
      const allowChange = beforeVisibleChangeCallback(nextVisible)
      if (isBoolean(allowChange) && !allowChange) {
        return false
      }
      const rootEl = document.querySelector(`#${rootId.value}`)
      // console.log('rootEl :>> ', rootEl)
      if (rootEl) {
        // remove first
        rootEl.innerHTML = ''
        rootEl.appendChild(dropdownItemsPanelId.value)
        rootEl.style.position = 'absolute'
        rootEl.classList.add(_拼样式名('popper'))
        changDropdownPanelPosition()
      }
      internalVisible.value = true
      emit(EMIT_EVENTS.VISIBLE_CHANGE, nextVisible)
    }

    const hideDropDown = () => {
      const nextVisible = false
      const allowChange = beforeVisibleChangeCallback(nextVisible)
      if (isBoolean(allowChange) && !allowChange) {
        return false
      }
      emit(EMIT_EVENTS.VISIBLE_CHANGE, nextVisible)
      setTimeout(() => {
        internalVisible.value = false
        removeOrEmptyRootPanel()
      }, 150)
    }

    const beforeVisibleChangeCallback = (nextVisible) => {
      if (
        nextVisible !== isDropdownVisible.value &&
        isFunction(props.beforeVisibleChange)
      ) {
        // next visible
        return props.beforeVisibleChange({
          nextVisible,
        })
      }
    }

    const removeOrEmptyRootPanel = () => {
      const rootEl = document.querySelector(`#${rootId.value}`)
      if (rootEl) {
        rootEl.innerHTML = ''
      }
    }

    const changDropdownPanelPosition = () => {
      const rootEl = document.querySelector(`#${rootId.value}`)
      if (rootEl) {
        // console.log(`changDropdownPanelPosition rootEl 👉`, rootEl)
        const { width: currentPanelWidth, height: currentPanelHeight } =
          rootEl.getBoundingClientRect()
        const triggerEl = vm.vnode.el.querySelector('.ve-dropdown-dt')

        const { height: triggerElHeight } = triggerEl.getBoundingClientRect()

        if (!popperAppendToEl) {
          return false
        }

        // is append to body
        const isAppendToBody = appendToElTagName.value === 'BODY'

        const {
          offsetLeft: triggerElLeft,
          offsetTop: triggerElTop,
          right: triggerElRight,
          bottom: triggerElBottom,
        } = isAppendToBody
          ? getViewportOffset(triggerEl)
          : getViewportOffsetWithinContainer(triggerEl, popperAppendToEl)

        let panelX = 0
        let panelY = 0

        // 如果不是添加到body需要考虑外层容器滚动调的影响
        let scrollLeft = 0
        let scrollTop = 0
        if (!isAppendToBody) {
          scrollLeft = popperAppendToEl.scrollLeft
          scrollTop = popperAppendToEl.scrollTop
        }

        // 右方宽度够显示
        if (triggerElRight >= currentPanelWidth) {
          panelX = triggerElLeft + scrollLeft
        } else {
          // 右方宽度不够显示在鼠标点击左方
          panelX = triggerElLeft - currentPanelWidth + scrollLeft
        }

        // 下方高度够显示
        if (triggerElBottom >= currentPanelHeight) {
          panelY =
            triggerElTop + triggerElHeight + props.defaultInstance + scrollTop
        } else {
          // 下方高度不够显示在鼠标点击上方
          panelY =
            triggerElTop -
            currentPanelHeight -
            props.defaultInstance +
            scrollTop
        }

        rootEl.style.left = panelX + 'px'
        rootEl.style.top = panelY + 'px'
      }
    }

    const setInputValue = () => {
      const labels = selectedLabels.value
      inputValue.value = labels.length > 0 ? labels.join() : ''
    }

    const dropdownPanelClick = () => {
      isDropdownShowTriggerClicked.value = true
      dropdownShowToggle()
    }

    const dropdownShowToggle = () => {
      if (isDropdownVisible.value) {
        hideDropDown()
      } else {
        showDropDown()
      }
    }

    const singleSelectOptionClick = (e, item) => {
      internalOptions.value = internalOptions.value.map((x) => {
        if (item.label === x.label) {
          x.selected = true
        } else {
          x.selected = false
        }
        return x
      })
      if (props.hideByItemClick) {
        hideDropDown()
      }
      if (props.isInput) {
        setInputValue()
      }
      // 使用户传入的v-model生效
      emit('input', internalOptions.value)
      emit(EMIT_EVENTS.ITEM_SELECT_CHANGE, internalOptions.value)
    }

    const getTextAlignClass = () => _拼样式名(`items-li-a-${props.textAlign}`)

    const dropdownClickOutside = () => {
      setTimeout(() => {
        if (isDropdownShowTriggerClicked.value) {
          isDropdownShowTriggerClicked.value = false
        } else {
          hideDropDown()
        }
      })
    }

    const checkedChangeControl = (item, isChecked) => {
      // console.log(`checkedChangeControl ing👇`)
      internalOptions.value = internalOptions.value.map((i) => {
        if (i.label === item.label) {
          i.selected = isChecked
        }
        return i
      })
      emit(EMIT_EVENTS.ITEM_SELECT_CHANGE, internalOptions.value)
    }

    const getRandomIdWithPrefix = () => _拼样式名(getRandomId())

    const addRootElementToElement = () => {
      rootId.value = getRandomIdWithPrefix()
      // dropdownItemsPanelId.value = getRandomIdWithPrefix()
      const rootEl = document.querySelector(`#${rootId.value}`)
      if (rootEl) {
        return false
      } else {
        return new Promise((resolve) => {
          const containerEl = document.createElement('div')
          containerEl.setAttribute('id', rootId.value)
          // console.log(
          //   `addRootElementToElement props.popperAppendTo 👉`,
          //   props.popperAppendTo
          // )
          if (
            typeof props.popperAppendTo === 'string' &&
            props.popperAppendTo.length > 0
          ) {
            popperAppendToEl.value = document.querySelector(
              props.popperAppendTo
            )
          } else {
            popperAppendToEl.value = props.popperAppendTo
          }
          appendToElTagName.value = popperAppendToEl.value.tagName
          popperAppendToEl.value.appendChild(containerEl)
          resolve()
        })
      }
    }

    onMounted(async () => {
      await addRootElementToElement()
      const targetEl =
        appendToElTagName.value === 'BODY' ? document : popperAppendToEl.value
      targetEl.addEventListener('scroll', changDropdownPanelPosition)
      window.addEventListener('resize', changDropdownPanelPosition)
      // console.log(`dropdownItemsPanelId.value 👉`, dropdownItemsPanelId.value)
    })

    onUnmounted(() => {
      removeOrEmptyRootPanel()
      const targetEl =
        appendToElTagName.value === 'BODY' ? document : popperAppendToEl.value
      targetEl.removeEventListener('scroll', changDropdownPanelPosition)
      window.removeEventListener('resize', changDropdownPanelPosition)
    })

    const getRef = (refName) => {
      console.log(`refName 👉`, refName)
      let vmref = vm.refs[refName]
      console.log(`vmref 👉`, vmref)
      return vmref
    }

    return () => {
      let content

      if (props.isMultiple) {
        content = internalOptions.value.map((item, index) => {
          const checkboxProps = {
            key: item.label,
            isControlled: true,
            label: item.label,
            showLine: item.showLine,
            isSelected: item.selected,
            onCheckedChange: (isChecked) =>
              checkedChangeControl(item, isChecked),
          }
          return (
            <li
              key={index}
              class={[
                _拼样式名('items-multiple'),
                _拼样式名('items-li'),
                getTextAlignClass(),
              ]}
            >
              <VeCheckbox {...checkboxProps} />
            </li>
          )
        })
      } else {
        // console.log(`props.isMultiple 👉`, props.isMultiple)
        content = internalOptions.value.map((item, index) => {
          const radioProps = {
            isControlled: true,
            isSelected: item.selected,
            'on-radio-change': () => {},
          }
          return (
            <li
              key={index}
              class={[_拼样式名('items-li'), item.selected ? 'active' : '']}
              onClick={(e) => singleSelectOptionClick(e, item)}
            >
              <a
                class={[_拼样式名('items-li-a'), getTextAlignClass()]}
                href="javascript:void(0)"
              >
                {props.showRadio ? (
                  <VeRadio {...radioProps}>{item.label}</VeRadio>
                ) : (
                  item.label
                )}
              </a>
            </li>
          )
        })
      }

      const dropdownProps = { class: ['ve-dropdown'] }

      // 获取指令对象
      // const clickOutsideDirective = resolveDirective('click-outside')
      // if (!clickOutsideDirective) {
      //   throw new Error('click-outside directive not found')
      // }

      const dropdownItemsProps = {
        ref: dropdownItemsPanelId,
        class: dropdownItemsClass.value,
      }
      const dropdownItems = withDirectives(
        <ul
          class={_拼样式名('items')}
          style={{
            'min-width': props.width + 'px',
            'max-width': props.getMaxWidth + 'px',
          }}
        >
          {/* custome content */}
          {props.isCustomContent && slots['custom-content']}
          {/* not custom content */}
          {!props.isCustomContent && (
            <div>
              <div
                style={{
                  'max-height': props.maxHeight + 'px',
                }}
                class={_拼样式名('items-warpper')}
              >
                {content}
              </div>
              {props.showOperation && (
                <li class={_拼样式名('operation')}>
                  <a
                    class={[
                      _拼样式名('operation-item'),
                      operationFilterClass.value,
                    ]}
                    href="javascript:void(0)"
                    onClick={reset}
                  >
                    {props.resetFilterText}
                  </a>
                  <a
                    class={[_拼样式名('operation-item')]}
                    href="javascript:void(0)"
                    onClick={confirm}
                  >
                    {props.confirmFilterText}
                  </a>
                </li>
              )}
            </div>
          )}
        </ul>,
        [[clickOutsideDirective, dropdownClickOutside]]
      )

      return (
        <dl {...dropdownProps}>
          <dt class="ve-dropdown-dt" onClick={dropdownPanelClick}>
            <a
              class={[props.isSelect ? _拼样式名('dt-selected') : '']}
              style={{ width: props.width + 'px' }}
            >
              {slots.default()}
            </a>
          </dt>
          <div style={{ display: 'none' }} class="yyyy">
            <dd {...dropdownItemsProps}>{dropdownItems}</dd>
          </div>
        </dl>
      )
    }
  },
})
